#include <iostream>
#include <string.h>
#include <iomanip>
#include <dirent.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <vector>
#include <pwd.h>
#include <grp.h>
#include <time.h>
//#include <stdlib.h>
using namespace std;

extern char *optarg;
extern int optind;

int l_flag = 0;
int a_flag = 0;
int R_flag = 0;
char filename[256][256];
char dirs[256][256];
int dirc = 0;
int len = 0;

int list_files(const char *dirname)
{
	struct dirent *entry;
	struct stat stt;
	DIR * dp = opendir(dirname);
	unsigned long size = 0;
	
	while(entry = readdir(dp))
	{
		if (a_flag == 0 && strncmp(entry->d_name,".",1) == 0)
		{
			continue;
		}

		char buf[256];
		strcpy(buf, dirname);
		strcat(buf, "/");
		strcat(buf, entry->d_name);
		int ret = lstat(buf,&stt); 
		if(ret < 0)
			exit(-1);

		if(S_ISDIR(stt.st_mode))
		{
			size += stt.st_blocks;
			strcpy(filename[len++],entry->d_name);
			//strcpy(filename[len++],buf);
			strcat(filename[len-1],"/");
			//strcat(buf, filename[len-1]);
		}
		else
		{	
			size += stt.st_blocks;
//			cout << "size:" << size << endl;
			strcpy(filename[len++],entry->d_name);
		//	strcpy(filename[len++],buf);
		}
	}
//	size = size/1.024;
	if (l_flag == 1)
		cout << "total " << size << endl;
	closedir(dp);
	return 0;
}

int stattest(const char *dirname, const char *filename)
{
	char buf[256];
	strcpy(buf, dirname);
	strcat(buf, "/");
	strcat(buf, filename);
	
	struct stat buff;
	struct passwd *p_passwd;
	struct group *p_group;
	struct tm *local;
	char p_time[128];
	
	lstat(buf,&buff);
	
	p_passwd = getpwuid(buff.st_uid);
	p_group = getgrgid(buff.st_gid);
	
	local = localtime(&(buff.st_mtime));
	
	if (S_ISDIR(buff.st_mode))
		cout << "d";
	else if (S_ISLNK(buff.st_mode))
		cout << "l";
	else
		cout << "-";
	if ((buff.st_mode & S_IRUSR))
		cout << "r";
	else
		cout << "-";
	if ((buff.st_mode & S_IWUSR))
		cout << "w";
	else
		cout << "-";
	if ((buff.st_mode & S_IXUSR))
		cout << "x";
	else
		cout << "x";
	if ((buff.st_mode & S_IRGRP))
		cout << "r";
	else
		cout << "-";
	if ((buff.st_mode & S_IWGRP))
		cout << "w";
	else
		cout << "-";
	if ((buff.st_mode & S_IXGRP))
		cout << "x";
	else
		cout << "-";
	if ((buff.st_mode & S_IROTH))
		cout << "r";
	else
		cout << "-";
	if ((buff.st_mode & S_IWOTH))
		cout << "w";
	else
		cout << "-";
	if ((buff.st_mode & S_IXOTH))
		cout << "x";
	else
		cout << "-";
	

	cout << " ";
	cout << setw(3) << buff.st_nlink << "  ";
	cout  << setw(1)<<p_passwd->pw_name << " " ;
	cout  << setw(2)<<p_group->gr_name << " ";
	cout << setw(10) << buff.st_size << " ";
	
	if (time(NULL) - buff.st_mtime > 15552000)
		strftime(p_time,128, "%b %e %G", local);
	else
		strftime(p_time,128, "%b %e %R", local);
	cout << p_time;
	if (S_ISLNK(buff.st_mode))
	{
		ssize_t r;
		char *linkname;
		linkname = (char*) malloc(buff.st_size + 1);
		r = readlink(buf, linkname, buff.st_size+1);
		if (r<0)
		{
			perror("readlink");
			exit(-1);
		}
		cout << " " << filename << " -> " << linkname;
	}
	else
		cout << " " << filename << " ";
	cout << endl;
	return 0;
}

int print_files(const char * dirname)
{	
	int i,j;
	int rank[256];
	int k = 0;

	for (i = 0 ; i < len ; i ++)
	{
		rank[i] = 0;
	}
	for (i = 0 ; i < len ; i ++)
	{
		for (j = 0 ; j < len ; j ++)
		{
			int temp;
			temp = strcmp(filename[i],filename[j]);
			if (temp > 0)
			{
				rank[i] += 1;
			}
			else if (temp < 0)
			{
				rank[i] = rank[i];
			}
			else if (temp == 0)
			{
				;
			}
		}
	}

	int count = 0;

	for (i = 0 ; i < len ; i ++)
	{
		for (j = 0 ; j < len ; j ++)
		{
			if (rank[j] == i)
			{
				if (l_flag == 1)
				{
					stattest(dirname, filename[j]);
				}
				else
				{
					printf("%-20s", filename[j]);
					++count;
					if(count == 6)
					{
						printf("\n");
						count = 0;
					}
				}
			}
		}
	}
	cout << endl;
	return 0;
}

void add_dir(const char * dir)
{
	strcpy(dirs[dirc], dir);
	dirc++;
	if (R_flag == 1)
	{
		struct dirent *entry;
		struct stat stt;
		DIR * dp = opendir(dir);

		while(entry = readdir(dp))
		{
			if (a_flag == 0 && strncmp(entry->d_name,".",1) == 0)
			{
				continue;
			}

			char buf[256];
			strcpy(buf, dir);
			strcat(buf, "/");
			strcat(buf, entry->d_name);
			int ret = lstat(buf,&stt); 
			if(ret < 0)
				exit(-1);

			if(S_ISDIR(stt.st_mode) && strcmp(entry->d_name,".") != 0 && strcmp(entry->d_name,"..") != 0)
			{
				add_dir(buf);
			}
			else
			{
				continue;
			}
		}

		closedir(dp);	
	}
}

int main(int argc, char *argv[])
{
	int i;
	char ch;
	struct stat directory;
	unsigned long size;

	while ((ch = getopt(argc, argv, "alR")) != -1)
	{
		switch(ch)
		{
			case 'a':
				a_flag = 1;
				break;
			case 'l':
				l_flag = 1;
				break;
			case 'R':
				R_flag = 1;
				break;
			default:
				cout << "This parameter is illegal." << endl;
				return 1;
		}
	}
	if (optind < argc)
	{
		for (i = optind; i < argc ; i ++)
		{	
			add_dir(argv[i]);
		}
	}
	else
	{
		add_dir(".");
	}

	for (i = 0; i < dirc; i ++)
	{
		len = 0;
		if(dirc >= 2)
			cout << dirs[i] << ":" << endl;

		list_files(dirs[i]);
		print_files(dirs[i]);
	}

	return 0;
}
